/**
 * AudioCacheUtil.js
 * 多端兼容（H5 / 小程序 / App）
 *
 * 用法：
 * import AudioCacheUtil from '@/utils/AudioCacheUtil.js';
 * AudioCacheUtil.play('hello', 'uk');
 * AudioCacheUtil.stop();
 */

import {getTts} from '@/api/wordHelper'

class AudioCacheUtil {
    static instance = null

    constructor() {
        this.cache = new Map()
        this.maxCacheSize = 1000
        this.playCounter = 0

        this.currentAudio = null
        this.currentKey = null
        this.isPlaying = false
    }

    static getInstance() {
        if (!AudioCacheUtil.instance) {
            AudioCacheUtil.instance = new AudioCacheUtil()
        }
        return AudioCacheUtil.instance
    }

    genKey(text, lan) {
        return `${lan}::${text.toLowerCase()}`
    }

    evictIfNeeded() {
        while (this.cache.size >= this.maxCacheSize) {
            let oldestKey = null
            let oldestUsed = Infinity
            for (const [key, value] of this.cache.entries()) {
                if (value.used < oldestUsed) {
                    oldestUsed = value.used
                    oldestKey = key
                }
            }
            if (oldestKey) {
                const entry = this.cache.get(oldestKey)
                if (entry.url && typeof URL !== 'undefined' && URL.revokeObjectURL) {
                    URL.revokeObjectURL(entry.url)
                }
                this.cache.delete(oldestKey)
            } else {
                break
            }
        }
    }

    /**
     * 获取音频URL
     * H5: 返回 blob URL
     * 小程序/App: 返回临时文件路径
     */
    async fetchAudio(text, lan) {
        // 小程序/App端：下载临时文件
        const baseURL = uni.$u.http.config.baseURL
        const token = uni.getStorageSync('token')
        const query = Object.keys({text, lan})
            .map(k => `${k}=${encodeURIComponent({text, lan}[k])}`)
            .join('&')

        return new Promise((resolve, reject) => {
            uni.downloadFile({
                url: `${baseURL}/wordHelper/getTts?${query}`,
                header: {
                    'Authorization': token ? 'Bearer ' + token : ''
                },
                success: (res) => {
                    if (res.statusCode === 200) {
                        resolve(res.tempFilePath)
                    } else {
                        reject(new Error('音频下载失败'))
                    }
                },
                fail: reject
            })
        })
    }

    stop() {
        if (this.currentAudio) {
            try {
                if (process.env.UNI_PLATFORM === 'h5') {
                    this.currentAudio.pause()
                } else {
                    this.currentAudio.stop()
                }
            } catch (err) {
                console.error('停止播放出错：', err)
            }
            this.currentAudio = null
            this.currentKey = null
            this.isPlaying = false
        }
    }

    async play(text, lan, speed = 1.0) {
        const key = this.genKey(text, lan)

        // 如果同一单词正在播放 → 停止播放
        if (this.currentKey === key && this.currentAudio) {
            this.stop()
            return
        }

        // 防止切换太快
        if (this.isPlaying) this.stop()

        let audioUrl
        if (this.cache.has(key)) {
            const item = this.cache.get(key)
            item.used = ++this.playCounter
            audioUrl = item.url
        } else {
            audioUrl = await this.fetchAudio(text, lan)
            this.cache.set(key, {url: audioUrl, used: ++this.playCounter})
            this.evictIfNeeded()
        }

        // 创建播放器实例
        if (process.env.UNI_PLATFORM === 'h5') {
            const audio = new Audio(audioUrl)
            audio.playbackRate = speed
            this.currentAudio = audio
            this.currentKey = key
            this.isPlaying = true

            audio.play().catch(err => console.error('音频播放失败', err))
            audio.addEventListener('ended', () => this.stop())
            audio.addEventListener('error', () => this.stop())
        } else {
            // 小程序 / App
            const innerAudio = uni.createInnerAudioContext()
            innerAudio.src = audioUrl
            innerAudio.playbackRate = speed
            this.currentAudio = innerAudio
            this.currentKey = key
            this.isPlaying = true

            innerAudio.play()
            innerAudio.onEnded(() => this.stop())
            innerAudio.onError(() => this.stop())
        }
    }
}

export default AudioCacheUtil.getInstance()
